{
	JFUNC - Jason's TP7 Library

	Contains common functions and some CRT replacements...
	Which is nice given it means I don't have to patch CRT for that stupid
	overflow bug or bloat out my code with write handlers I'm not even going
	to use.
}

unit jfunc;

interface

const
  continueString='Press any key to continue';

type
{
	a few pointer types I use a lot
}
	pChar=^char;
	pByte=^byte;
{
	I like to shorthand my string declarations too
}
	dosExt=string[3];
	dosName=string[8];
	hexWordString=string[4];
	hexLongString=string[8];
	st10=string[10];
	st20=string[20];
	st40=string[40];
	st80=string[80];
	st255=string[255];

function stackAvail:word;
function dosAvail:longint;
function strint(n:longint; digits:byte):st10;
function strLead(n:longint; digits:byte):st10;
function word2Hex(v:word):hexWordString;
function long2Hex(v:longint):hexLongString;
function str2Upper(str:string):string;
function str2Lower(str:string):string;
function paramExists(st:string):boolean;
function getIntVec(interrupt:byte):pointer;
procedure setIntVec(interrupt:byte; address:pointer);
function keypressed:boolean;
function readkey:char;
procedure waitkey;
procedure writeText(section:st20);


implementation

const
  hexChar:array[0..15] of char=(
  	'0','1','2','3','4','5','6','7',
  	'8','9','A','B','C','D','E','F'
  );

{
	memory functions that SHOULD have been included in the
	system library for Turbo IMHO
}

function stackAvail:word; assembler;
asm
	mov  ax,sp
end;

function dosAvail:longint; assembler;
asm
	mov  ax,$4800
	mov  bx,$FFFF { 1 meg, impossible }
	int  $21
	xor  dx,dx
	mov  ax,bx
	mov  bx,16
	mul  bx
end;

{ pain in the ass STR doesn't work as a function... so make one! }

function strint(n:longint; digits:byte):st10;
var
  st:st10;
begin
  str(n:digits,st);
  strint:=st;
end;

{ Typically I use strLead to format score totals in games }

function strLead(n:longint; digits:byte):st10;
var
	st:st10;
	ln:longint;
	decdig:byte;
begin
	st:='';
	decDig:=digits;
	ln:=n;
	while (decDig>0) do begin
		st:=chr((n mod 10)+48)+st;
		n:=n div 10;
		dec(decDig);
	end;
	strLead:=st;
end;

function word2Hex(v:word):hexWordString;
var
	t,n:word;
  s:string;
begin
	t:=0;
	s:='';
	n:=v;
	for t:=0 to 3 do begin
		s:=hexChar[n and $0F]+s;
		n:=n shr 4;
	end;
  word2hex:=s;
end;

function long2Hex(v:longint):hexLongString;
var
	t:word;
	n:longint;
  s:string;
begin
	t:=0;
	s:='';
	n:=v;
	for t:=0 to 7 do begin
		s:=hexChar[n and $0F]+s;
		n:=n shr 4;
	end;
  long2Hex:=s;
end;

{
	strConvert loosely based on the str2Upper inline
	assembler example in the TP7 manual.

	STR   - string to convert
	TEST  - two bytes
			lower byte = first character to convert
			lower byte = last character to convert

			for example:
				$7A61 == 'a..z'
				$5A41 == 'A..Z'

	AMT  - equals amount to change, usually +$20 or -$20
}

function strConvert(str:string; test:word; amt:shortInt):string; assembler;
asm
	{
		we're not using DX, so store DS in it instead of
		waiting for the stack. 19 clocks vs. 8?
	}
	mov  dx,ds
	{
		store variables before messing with DS:SI
	}
	mov  bx,test
	mov  ch,amt

	les  di,@result
	lds  si,str

	cld
	lodsb
	stosb

	xor  ah,ah
	xchg cx,ax
	jcxz @noAction

	mov  bx,test
	mov  ah,amt

@loop:
	lodsb
	cmp  al,bl
	jb   @noChange
	cmp  al,bh
	ja   @noChange
	add  al,ah
@noChange:
	stosb
	loop @loop

@noAction:
	mov  ds,dx
end; {strConvert}

function str2Upper(str:string):string;
begin
	str2Upper:=strConvert(str,$7A61,-$20);
end;

function str2Lower(str:string):string;
begin
	str2Lower:=strConvert(str,$5A41,$20);
end;

function paramExists(st:string):boolean;
var
	tst:string;
	t:word;
	result:boolean;
begin
	t:=0;
	result:=false;
	tst:=str2Upper(st);
	while (t<paramCount) do begin
		inc(t);
		if (str2Upper(paramStr(t))=tst) then begin
			result:=true;
			t:=paramCount;
		end;
	end;
	paramExists:=result;
end;

function getIntVec(interrupt:byte):pointer; assembler;
asm
	mov  al,interrupt;
	mov  ah,$35
	int  $21
	mov  ax,bx
	mov  dx,es
end;

procedure setIntVec(interrupt:byte; address:pointer); assembler;
asm
	push ds
	mov  al,interrupt
	mov  ah,$25
	lds  dx,address
	int  $21
	pop  ds
end;

{
	Calling DOS for keyboard handling, avoids headaches trying
	to support the PcJr/Tandy1K as well as the differences between
	AT and XT on the keymaps.
}

function readkey:char; assembler;
asm
	mov  ah,$07
	int  $21
end;

function keypressed:boolean; assembler;
asm
	mov  ah,$0B
	int  $21
end;

procedure waitkey;
begin
	while keypressed do readkey;
	readkey;
end;

procedure writeText(section:st20);
var
	f:text;
	tst:st80;
	compareSt:st20;
	t:word;
begin
	assign(f,'TEXTS.TDT');
	reset(f);
	compareSt:='@'+str2Lower(section);
	repeat
		readln(f,tst);
	until eof(f) or (tst=compareSt);
	if not(eof(f)) then repeat
		readln(f,tst);
		if not(tst='@end') then begin
			if (tst='****') then begin
				write(continueString);
				waitkey;
				for t:=1 to length(continueString) do write(#8,#32,#8);
			end else writeln(tst);
		end;
	until eof(f) or (tst='@end');
	close(f);
end;

end.